package com.xm.webSocket;

import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.xm.common.constant.CommonConstant.FILE_PATH;

@Component
public class LogWebSocketHandler extends TextWebSocketHandler {
    
    private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
    private final ExecutorService executorService = Executors.newCachedThreadPool();
    private final Map<String, AtomicBoolean> tailFlags = new ConcurrentHashMap<>();
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionId = session.getId();
        sessions.put(sessionId, session);
        
        // 创建标志以控制日志监控线程
        AtomicBoolean keepTailing = new AtomicBoolean(true);
        tailFlags.put(sessionId, keepTailing);
        
        // 启动日志监控线程
        executorService.submit(() -> tailLog(session, keepTailing, FILE_PATH));
    }
    
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String sessionId = session.getId();
        // 停止日志监控线程
        AtomicBoolean flag = tailFlags.get(sessionId);
        if (flag != null) {
            flag.set(false);
        }
        
        // 清理资源
        sessions.remove(sessionId);
        tailFlags.remove(sessionId);
    }
    
    private void tailLog(WebSocketSession session, AtomicBoolean keepTailing, String logFilePath) {
        try {
            Path path = Paths.get(logFilePath);
            if (!Files.exists(path)) {
                session.sendMessage(new TextMessage("Log file does not exist: " + logFilePath));
                return;
            }
            
            // 先读取最后1000行日志以提供上下文
            sendLastNLines(session, logFilePath, 1000);
            
            // 然后开始实时监控
            RandomAccessFile file = new RandomAccessFile(logFilePath, "r");
            long filePointer = file.length();
            
            // 持续监控日志文件
            while (keepTailing.get() && session.isOpen()) {
                long length = file.length();
                if (length < filePointer) {
                    // 日志文件被截断，重新开始读取
                    file.seek(0);
                    filePointer = 0;
                }
                
                if (length > filePointer) {
                    // 有新的日志内容
                    file.seek(filePointer);
                    String line;
                    while ((line = file.readLine()) != null && session.isOpen()) {
                        session.sendMessage(new TextMessage(new String(line.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)));
                    }
                    filePointer = file.getFilePointer();
                }
                
                // 休眠一段时间后继续检查
                Thread.sleep(500);
            }
            
            file.close();
        } catch (Exception e) {
            try {
                session.sendMessage(new TextMessage("Error reading log file: " + e.getMessage()));
            } catch (Exception ex) {
                // 忽略发送错误
            }
        }
    }
    
    private void sendLastNLines(WebSocketSession session, String logFilePath, int n) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader(logFilePath));
            String[] lines = new String[n];
            int currentIndex = 0;
            int totalLines = 0;
            String line;
            
            while ((line = reader.readLine()) != null) {
                lines[currentIndex] = line;
                currentIndex = (currentIndex + 1) % n;
                totalLines++;
            }
            
            reader.close();
            
            // 计算实际需要发送的行数
            int linesToSend = Math.min(totalLines, n);
            int startIndex = totalLines >= n ? currentIndex : 0;
            
            // 发送日志行
            for (int i = 0; i < linesToSend; i++) {
                int index = (startIndex + i) % n;
                session.sendMessage(new TextMessage(lines[index]));
            }
            
        } catch (Exception e) {
            try {
                session.sendMessage(new TextMessage("Error reading initial log content: " + e.getMessage()));
            } catch (Exception ex) {
                // 忽略发送错误
            }
        }
    }
}
